home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #1 / Ham Radio 2000.iso / ham2000 / tcp_ip / wnos / wn941101 / ftpserv.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-10-04  |  19.4 KB  |  772 lines

  1. /* FTP Server state machine - see RFC 959 */
  2. #include <stdio.h>
  3. #include <ctype.h>
  4. #include <time.h>
  5. #ifdef    __TURBOC__
  6. #include <io.h>
  7. #include <dir.h>
  8. #endif
  9. #include "global.h"
  10. #include "mbuf.h"
  11. #include "proc.h"
  12. #include "socket.h"
  13. #include "dirutil.h"
  14. #include "commands.h"
  15. #include "files.h"
  16. #include "ftp.h"
  17. #include "ftpserv.h"
  18.  
  19. static void ftpserv __ARGS((int s,void *unused,void *p));
  20. static int near sendit __ARGS((struct ftpserv *ftp,char *command,char *file,long offset));
  21. static int near recvit __ARGS((struct ftpserv *ftp,char *command,char *file));
  22. static void near ftplogin __ARGS((struct ftpserv *ftp,char *pass));
  23. static int near pport __ARGS((struct sockaddr_in *sock,char *arg));
  24.  
  25. /* Response messages */
  26. static char binwarn[]     = "100 Warning: type is ASCII and %s appears to be binary\n";
  27. static char sending[]     = "150 Opening data connection for %s %s\n";
  28. static char typeok[]     = "200 Type %s OK\n";
  29. static char mkdok[]     = "200 MKD ok\n";
  30. static char portok[]     = "200 Port command okay\n";
  31. static char okay[]     = "200 Ok\n";
  32. static char help[]    = "214-The following commands are recognized (* =>'s unimplemented)\n"
  33.               "214-    ACCT*  CWD   DELE  HELP  LIST  MODE\n"
  34.               "214-    MKD    NAME* NOOP  NLST  PASS  PORT\n"
  35.               "214-    PWD    QUIT  REST  RMD   STOR  STRU*\n"
  36.               "214-    SREST* SYST  USER  XMKD  XRMD  XPWD\n"
  37.               "214 Direct bugs to ftp-bugs@%s\n";
  38. static char syst[]    = "215 UNIX Type: L8\n";
  39. static char banner[]     = "220 %s FTP version %s ready at %s\n";
  40. static char bye[]     = "221 Goodbye!\n";
  41. static char rxok[]     = "226 File received OK\n";
  42. static char txok[]     = "226 File sent OK\n";
  43. static char logged[]     = "230 Logged in\n";
  44. static char deleok[]     = "250 File deleted\n";
  45. static char pwdmsg[]     = "257 %s is current directory\n";
  46. static char givepass[]     = "331 Enter PASS command\n";
  47. static char lowmem[]     = "421 System overloaded\n";
  48. static char noconn[]     = "425 Data connection reset\n";
  49. static char badcmd[]     = "500 Unknown command\n";
  50. static char unsupp[]     = "500 Unsupported command or option\n";
  51. static char only8[]     = "501 Only logical bytesize 8 supported\n";
  52. static char badtype[]     = "501 Unknown type %s\n";
  53. static char badport[]     = "501 Bad port syntax\n";
  54. static char unimp[]     = "502 Command not yet implemented\n";
  55. static char userfirst[] = "503 Login with USER first.\n";
  56. static char notlog[]     = "530 Please log in with USER and PASS\n";
  57. static char delefail[]     = "550 Delete failed: %s\n";
  58. static char writerr[]     = "552 Write error: %s\n";
  59. static char nodir[]     = "553 Can't read %s: %s\n";
  60. static char cantmake[]     = "553 Can't create %s: %s\n";
  61. static char nopos[]    = "554 Can't position %s\n";
  62. static char noperm[]     = "550 Permission denied\n";
  63.  
  64. static int Sftp = -1;    /* Prototype socket for service */
  65.  
  66. int32 Ftptdiscinit;
  67.     
  68. /* Set ftp redundancy timer */
  69. int
  70. doftptdisc(argc,argv,p)
  71. int argc;
  72. char *argv[];
  73. void *p;
  74.     {
  75.         return setlong(&Ftptdiscinit,"Ftp redundancy timer (sec)",argc,argv);
  76.         }
  77.  
  78. /* Start up FTP service */
  79. int
  80. ftpstart(argc,argv,p)
  81. int argc;
  82. char *argv[];
  83. void *p;
  84. {
  85.     struct sockaddr_in lsocket;
  86.     int s;
  87.  
  88.     if(Sftp != -1){
  89.         /* Already running! */
  90.         return 0;
  91.     }
  92.     psignal(Curproc,0);    /* Don't keep the parser waiting */
  93.     chname(Curproc,"FTP listener");
  94.  
  95.     lsocket.sin_family = AF_INET;
  96.     lsocket.sin_addr.s_addr = INADDR_ANY;
  97.     lsocket.sin_port = (argc < 2) ? IPPORT_FTP : atoi(argv[1]);
  98.  
  99.     Sftp = socket(AF_INET,SOCK_STREAM,0);
  100.     bind(Sftp,(char *)&lsocket,sizeof(lsocket));
  101.     listen(Sftp,1);
  102.     for(;;){
  103.         if((s = accept(Sftp,NULLCHAR,(int *)NULL)) == -1)
  104.             break;    /* Service is shutting down */
  105.  
  106.         if(availmem() < Memthresh){
  107.             usputs(s,lowmem);
  108.             shutdown(s,1);
  109.         } else {
  110.             /* Spawn a server */
  111.             newproc("ftpserv",1536,ftpserv,s,NULL,NULL,0);
  112.         }
  113.     }
  114.     return 0;
  115. }
  116.  
  117. /* Shut down FTP server */
  118. int
  119. ftp0(argc,argv,p)
  120. int argc;
  121. char *argv[];
  122. void *p;
  123. {
  124.     close_s(Sftp);
  125.     Sftp = -1;
  126.     return 0;
  127. }
  128.  
  129. static int near
  130. pport(sock,arg)
  131. struct sockaddr_in *sock;
  132. char *arg;
  133. {
  134.     int32 n;
  135.     int i;
  136.  
  137.     for(i = 0, n = 0; i < 4; i++) {
  138.         n = atoi(arg) + (n << 8);
  139.         if((arg = strchr(arg,',')) == NULLCHAR)
  140.             return -1;
  141.         arg++;
  142.     }
  143.     sock->sin_addr.s_addr = n;
  144.     n = atoi(arg);
  145.     if((arg = strchr(arg,',')) == NULLCHAR)
  146.         return -1;
  147.     arg++;
  148.     n = atoi(arg) + (n << 8);
  149.     sock->sin_port = n;
  150.     return 0;
  151. }
  152.  
  153. #define PATHLEN        100
  154.  
  155. /* Attempt to log in the user whose name is in ftp->username and password
  156.  * in pass
  157.  */
  158. static void near
  159. ftplogin(ftp,pass)
  160. struct ftpserv *ftp;
  161. char *pass;
  162. {
  163.     int anony = 0;
  164.  
  165.     ftp->path = mxallocw(PATHLEN);
  166.     if((ftp->perms = userlogin(ftp->username,pass,&ftp->path,PATHLEN,&anony)) == (char)-1) {
  167.         anony = 1;
  168.         if((ftp->perms = userlogin("anonymous",pass,&ftp->path,PATHLEN,&anony)) == (char)-1) {
  169.             anony = 2;
  170.         }
  171.     }
  172.     /* Set up current directory and path prefix */
  173.     if(anony != 2) {
  174.         ftp->cd = strxdup(ftp->path);
  175.         log(ftp->control,"FTP  open %s %s",ftp->username,anony ? pass : "");
  176.     } else {
  177.         xfree(ftp->path);
  178.         ftp->path = NULLCHAR;
  179.         ftp->perms = 0;
  180.     }
  181.     usputs(ftp->control,(anony != 2) ? logged : noperm);
  182.     return;
  183. }
  184.  
  185. static void
  186. ftpserv(s,unused,p)
  187. int s;    /* Socket with user connection */
  188. void *unused;
  189. void *p;
  190. {
  191.     struct ftpserv *ftp;
  192.     char **cmdp, buf[512], *arg, *cp, *cp1, *file, *mode;
  193.     long t, restpos;
  194.     int cnt, i, cmdnum;
  195.     struct sockaddr_in socket;
  196.  
  197.     /* Command table */
  198.     char *commands[] = {
  199.         "user",
  200.         "acct",
  201.         "pass",
  202.         "type",
  203.         "list",
  204.         "cwd",
  205.         "dele",
  206.         "name",
  207.         "quit",
  208.         "retr",
  209.         "stor",
  210.         "port",
  211.         "nlst",
  212.         "pwd",
  213.         "xpwd",            /* For compatibility with 4.2BSD */
  214.         "mkd ",
  215.         "xmkd",            /* For compatibility with 4.2BSD */
  216.         "xrmd",            /* For compatibility with 4.2BSD */
  217.         "rmd ",
  218.         "stru",
  219.         "mode",
  220.         "help",
  221.         "rest",
  222.         "noop",
  223.         "syst",
  224.         NULLCHAR
  225.     };
  226.  
  227.     sockmode(s,SOCK_ASCII);
  228.     ftp = (struct ftpserv *)mxallocw(sizeof(struct ftpserv));
  229.  
  230.     ftp->data = -1;
  231.  
  232.     sockowner(s,Curproc);        /* We own it now */
  233.     ftp->control = s;
  234.     /* Set default data port */
  235.     i = SOCKSIZE;
  236.     getpeername(s,(char *)&socket,&i);
  237.     socket.sin_port = IPPORT_FTPD;
  238.     ASSIGN(ftp->port,socket);
  239.  
  240.     log(s,"FTP  open");
  241.     time(&t);
  242.     cp = ctime(&t);
  243.     if((cp1 = strchr(cp,'\n')) != NULLCHAR)
  244.         *cp1 = '\0';
  245.     usprintf(s,banner,Hostname,Version,cp);
  246.     usflush(s);
  247. loop:
  248.     /* Time-out after some inactivity time */
  249.     alarm((long)(Ftptdiscinit*1000L));
  250.     if((cnt = recvline(s,buf,sizeof(buf))) == -1){
  251.         /* He closed on us */
  252.         goto finish;
  253.     }
  254.     alarm(0L);
  255.     if(cnt == 0){
  256.         /* Can't be a legal FTP command */
  257.         usprintf(ftp->control,badcmd);
  258.         goto loop;
  259.     }
  260.     rip(buf);
  261. #ifdef    UNIX
  262.     /* Translate first word to lower case */
  263.     for(cp = buf;*cp != ' ' && *cp != '\0';cp++)
  264.         *cp = tolower(*cp);
  265. #else
  266.     /* Translate entire buffer to lower case */
  267.     for(cp = buf;*cp != '\0';cp++)
  268.         *cp = tolower(*cp);
  269. #endif
  270.     /* Find command in table; if not present, return syntax error */
  271.     for(cmdp = commands; *cmdp != NULLCHAR; cmdp++)
  272.         if(strncmp(*cmdp,buf,strlen(*cmdp)) == 0)
  273.             break;
  274.     if(*cmdp == NULLCHAR){
  275.         usprintf(ftp->control,unsupp);
  276.         goto loop;
  277.     }
  278.     /* Allow only USER, PASS and QUIT before logging in */
  279.     if(ftp->cd == NULLCHAR || ftp->path == NULLCHAR){
  280.         switch((int)(cmdp - commands)) {
  281.         case USER_CMD:
  282.         case PASS_CMD:
  283.         case QUIT_CMD:
  284.         case HELP_CMD:
  285.             break;
  286.         default:
  287.             usprintf(ftp->control,notlog);
  288.             goto loop;
  289.         }
  290.     }
  291.  
  292.     arg = &buf[strlen(*cmdp)];
  293.     while(*arg == ' ')
  294.         arg++;
  295.  
  296.     /* Execute specific command */
  297.     switch(cmdnum = (int)(cmdp-commands)) {
  298.     case USER_CMD:
  299.         xfree(ftp->username);
  300.         ftp->username = strxdup(arg);
  301.         usprintf(ftp->control,givepass);
  302.         break;
  303.     case TYPE_CMD:
  304.         strupr(arg);
  305.         switch(arg[0]) {
  306.         case 'A':    /* Ascii */
  307.             ftp->type = ASCII_TYPE;
  308.             usprintf(ftp->control,typeok,arg);
  309.             break;
  310.         case 'L':
  311.             while(*arg != ' ' && *arg != '\0')
  312.                 arg++;
  313.             if(*arg == '\0' || *++arg != '8'){
  314.                 usprintf(ftp->control,only8);
  315.                 break;
  316.             }
  317.             ftp->type = LOGICAL_TYPE;
  318.             ftp->logbsize = 8;
  319.             usprintf(ftp->control,typeok,arg);
  320.             break;
  321.         case 'B':    /* Binary */
  322.         case 'I':    /* Image */
  323.             ftp->type = IMAGE_TYPE;
  324.             usprintf(ftp->control,typeok,arg);
  325.             break;
  326.         default:    /* Invalid */
  327.             usprintf(ftp->control,badtype,arg);
  328.             break;
  329.         }
  330.         break;
  331.     case QUIT_CMD:
  332.         usprintf(ftp->control,bye);
  333.         goto finish;
  334.      case REST_CMD:
  335.         /*--------------------------------------------------------------*
  336.         * Restart request comes in at this point. Try to find 'remote-  *
  337.         * file, check offset.                                           *
  338.         * refuse if pass EOF else advance and initiate transfer         *
  339.         *---------------------------------------------------------------*/
  340.         file = strchr(arg,' ');
  341.         restpos = atol(file);
  342.         *file = 0;
  343.     case RETR_CMD:
  344.         file = pathname(ftp->cd,arg);
  345.         switch(ftp->type){
  346.         case IMAGE_TYPE:
  347.         case LOGICAL_TYPE:
  348.             mode = READ_BINARY;
  349.             break;
  350.         case ASCII_TYPE:
  351.             mode = READ_TEXT;
  352.             break;
  353.         }
  354.         if(!permcheck(ftp->path,ftp->perms,RETR_CMD,file)){
  355.              usprintf(ftp->control,noperm);
  356.         } else if((ftp->fp = open_file(file,mode,ftp->control,0)) != NULLFILE) {
  357.             if(ftp->type == ASCII_TYPE && isbinary(ftp->fp)){
  358.                 usprintf(ftp->control,binwarn,file);
  359.             }
  360.             if (cmdnum == REST_CMD)   { /*dk5dc*/
  361.                 log(ftp->control,"FTP  REST: %s",file);
  362.                 sendit(ftp,"REST",file,restpos);
  363.             }else {
  364.                 restpos = 0;
  365.                 log(ftp->control,"FTP  RETR: %s",file);
  366.                 sendit(ftp,"RETR",file,restpos);
  367.             }
  368.         }
  369.         xfree(file);
  370.         break;
  371.     case STOR_CMD:
  372.         file = pathname(ftp->cd,arg);
  373.         switch(ftp->type){
  374.         case IMAGE_TYPE:
  375.         case LOGICAL_TYPE:
  376.             mode = WRITE_BINARY;
  377.             break;
  378.         case ASCII_TYPE:
  379.             mode = WRITE_TEXT;
  380.             break;
  381.         }
  382.         if(!permcheck(ftp->path,ftp->perms,STOR_CMD,file)){
  383.              usprintf(ftp->control,noperm);
  384.         } else if((ftp->fp = open_file(file,mode,ftp->control,1)) != NULLFILE) {
  385.             log(ftp->control,"FTP  STOR %s",file);
  386.             recvit(ftp,"STOR",file);
  387.         }
  388.         xfree(file);
  389.         break;
  390.     case PORT_CMD:
  391.         if(pport(&ftp->port,arg) == -1){
  392.             usprintf(ftp->control,badport);
  393.         } else {
  394.             usprintf(ftp->control,portok);
  395.         }
  396.         break;
  397. #ifndef CPM
  398.     case LIST_CMD:
  399.         file = pathname(ftp->cd,arg);
  400.         if(!permcheck(ftp->path,ftp->perms,RETR_CMD,file)){
  401.              usprintf(ftp->control,noperm);
  402.         } else if((ftp->fp = dir(file,1)) == NULLFILE){
  403.             usprintf(ftp->control,nodir,file,sys_errlist[errno]);
  404.         } else {
  405.             sendit(ftp,"LIST",file,0L);
  406.         }
  407.         xfree(file);
  408.         break;
  409.     case NLST_CMD:
  410.         file = pathname(ftp->cd,arg);
  411.         if(!permcheck(ftp->path,ftp->perms,RETR_CMD,file)){
  412.              usprintf(ftp->control,noperm);
  413.         } else if((ftp->fp = dir(file,0)) == NULLFILE){
  414.             usprintf(ftp->control,nodir,file,sys_errlist[errno]);
  415.         } else {
  416.             sendit(ftp,"NLST",file,0L);
  417.         }
  418.         xfree(file);
  419.         break;
  420.     case CWD_CMD:
  421.         file = pathname(ftp->cd,arg);
  422.         if(!permcheck(ftp->path,ftp->perms,RETR_CMD,file)){
  423.              usprintf(ftp->control,noperm);
  424.             xfree(file);
  425. #ifdef    MSDOS
  426.         /* Don'tcha just LOVE %%$#@!! MS-DOS? */
  427.         } else if(strcmp(file,"/") == 0 || access(file,0) == 0){
  428. #else
  429.         } else if(access(file,0) == 0){    /* See if it exists */
  430. #endif
  431.             /* Succeeded, record in control block */
  432.             xfree(ftp->cd);
  433.             ftp->cd = file;
  434.             usprintf(ftp->control,pwdmsg,file);
  435.         } else {
  436.             /* Failed, don't change anything */
  437.             usprintf(ftp->control,nodir,file,sys_errlist[errno]);
  438.             xfree(file);
  439.         }
  440.         break;
  441.     case XPWD_CMD:
  442.     case PWD_CMD:
  443.         usprintf(ftp->control,pwdmsg,ftp->cd);
  444.         break;
  445. #else
  446.     case LIST_CMD:
  447.     case NLST_CMD:
  448.     case CWD_CMD:
  449.     case XPWD_CMD:
  450.     case PWD_CMD:
  451. #endif
  452.     case ACCT_CMD:
  453.         usprintf(ftp->control,unimp);
  454.         break;
  455.     case DELE_CMD:
  456.         file = pathname(ftp->cd,arg);
  457.         if(!permcheck(ftp->path,ftp->perms,DELE_CMD,file)){
  458.              usprintf(ftp->control,noperm);
  459.         } else if(unlink(file) == 0){
  460.             log(ftp->control,"FTP  DELE %s",file);
  461.             usprintf(ftp->control,deleok);
  462.         } else {
  463.             usprintf(ftp->control,delefail,sys_errlist[errno]);
  464.         }
  465.         xfree(file);
  466.         break;
  467.     case PASS_CMD:
  468.         if(ftp->username == NULLCHAR)
  469.             usprintf(ftp->control,userfirst);
  470.         else
  471.             ftplogin(ftp,arg);
  472.         break;
  473. #ifndef    CPM
  474.     case XMKD_CMD:
  475.     case MKD_CMD:
  476.         file = pathname(ftp->cd,arg);
  477.         if(!permcheck(ftp->path,ftp->perms,MKD_CMD,file)){
  478.             usprintf(ftp->control,noperm);
  479. #ifdef    UNIX
  480.         } else if(mkdir(file,0777) == 0){
  481. #else
  482.         } else if(mkdir(file) == 0){
  483. #endif
  484.             log(ftp->control,"FTP  MKD %s",file);
  485.             usprintf(ftp->control,mkdok);
  486.         } else {
  487.             usprintf(ftp->control,cantmake,file,sys_errlist[errno]);
  488.         }
  489.         xfree(file);
  490.         break;
  491.     case XRMD_CMD:
  492.     case RMD_CMD:
  493.         file = pathname(ftp->cd,arg);
  494.         if(!permcheck(ftp->path,ftp->perms,RMD_CMD,file)){
  495.              usprintf(ftp->control,noperm);
  496.         } else if(rmdir(file) == 0){
  497.             log(ftp->control,"FTP  RMD %s",file);
  498.             usprintf(ftp->control,deleok);
  499.         } else {
  500.             usprintf(ftp->control,delefail,sys_errlist[errno]);
  501.         }
  502.         xfree(file);
  503.         break;
  504.     case STRU_CMD:
  505.         if(tolower(arg[0]) != 'f')
  506.             usprintf(ftp->control,unsupp);
  507.         else
  508.             usprintf(ftp->control,okay);
  509.         break;
  510.     case MODE_CMD:
  511.         if(tolower(arg[0]) != 's')
  512.             usprintf(ftp->control,unsupp);
  513.         else
  514.             usprintf(ftp->control,okay);
  515.         break;
  516.     case NOOP_CMD:
  517.         usprintf(ftp->control,okay);
  518.         break;
  519.     case SYST_CMD:
  520.         usprintf(ftp->control,syst);
  521.         break;
  522.     case HELP_CMD:
  523.         usprintf(ftp->control,help,Hostname);
  524.         break;
  525.  
  526.     default:
  527.         usprintf(ftp->control,unsupp);
  528.         break;
  529.     }
  530. #endif
  531.     goto loop;
  532. finish:
  533.     log(ftp->control,"FTP  close");
  534.     /* Clean up */
  535.     close_s(ftp->control);
  536.     if(ftp->data != -1)
  537.         close_s(ftp->data);
  538.     if(ftp->fp != NULLFILE)
  539.         fclose(ftp->fp);
  540.     xfree(ftp->username);
  541.     xfree(ftp->path);
  542.     xfree(ftp->cd);
  543.     xfree((char *)ftp);
  544. }
  545.  
  546. /* Subroutine for logging in the user whose name is name and password is pass.
  547.    The buffer path should be long enough to keep a line from the userfile.
  548.    If pwdignore is true, the password check will be overridden.
  549.    The return value is the permissions field, -1 if the login failed.
  550.    Path is set to point at the path field, and pwdignore will be true if no
  551.    particular password was needed for this user.
  552.  */
  553. int
  554. userlogin(name,pass,path,len,pwdignore)
  555. char *name;
  556. char *pass;
  557. char **path;
  558. int len;            /* Length of buffer pointed at by *path */
  559. int *pwdignore;
  560. {
  561.     char *cp,*cp1;
  562.     FILE *fp;
  563.     int anony,perm;
  564.  
  565.     if((fp = fopen(Userfile,READ_TEXT)) == NULLFILE)
  566.         /* Userfile doesn't exist */
  567.         return -1;
  568.     while(fgets(*path,len,fp),!feof(fp)){
  569.         if(*path[0] == '#')
  570.             continue;    /* Comment */
  571.         if((cp = strpbrk(*path," \t")) == NULLCHAR)
  572.             /* Bogus entry */
  573.             continue;
  574.         *cp++ = '\0';        /* Now points to password */
  575.         if(stricmp(name,*path) == 0)
  576.             break;        /* Found user name */
  577.     }
  578.     if(feof(fp)){
  579.         /* User name not found in file */
  580.         fclose(fp);
  581.         return -1;
  582.     }
  583.     fclose(fp);
  584.  
  585.     /* Look for space after password field in file */
  586.     if((cp1 = strpbrk(cp," \t")) == NULLCHAR)
  587.         /* Invalid file entry */
  588.         return -1;
  589.     *cp1++ = '\0';    /* Now points to path field */
  590.  
  591.     anony = (*cp == '*') ? 3 : *pwdignore;
  592.  
  593.     if(!anony && strcmp(cp,pass) != 0)
  594.         /* Password required, but wrong one given */
  595.         anony = 2;        /* DB3FL */
  596.     if((cp = strpbrk(cp1," \t")) == NULLCHAR)
  597.         /* Permission field missing */
  598.         return -1;
  599.     *cp++ = '\0';    /* now points to permission field */
  600.     perm = atoi(cp);
  601. #if   defined(AMIGA)
  602.     /*
  603.      * Well, on the Amiga, a file can be referenced by many names:
  604.      * device names (DF0:) or volume names (My_Disk:).  This hunk of code
  605.      * passed the pathname specified in the ftpusers file, and gets the
  606.      * absolute path copied into the user's buffer.  We really should just
  607.      * allocate the buffer and return a pointer to it, since the caller
  608.      * really doesn't have a good idea how long the path string is..
  609.      */
  610.     cp1 = pathname("", cp1);
  611.     if (cp1)
  612.         strcpy(*path, cp1);
  613.     else
  614.         **path = '\0';
  615.     xfree(cp1);
  616. #else
  617.     strcpy(*path,cp1);
  618.     /* Convert any backslashes to forward slashes, for backward
  619.      * compatibility with the old NET
  620.      */
  621.     while((cp = strchr(*path,'\\')) != NULLCHAR)
  622.         *cp = '/';
  623. #endif
  624.     *pwdignore = anony;
  625.  
  626.     /* Finally return the permission bits */
  627.     return perm;
  628. }
  629.  
  630. #ifdef    MSDOS
  631. /* Illegal characters in a DOS filename */
  632. static char badchars[] = "\"[]|<>+=;,";
  633. #endif
  634.  
  635. /* Return 1 if the file operation is allowed, 0 otherwise */
  636. int
  637. permcheck(path,perms,op,file)
  638. char *path;
  639. int perms;
  640. int op;
  641. char *file;
  642. {
  643. #ifdef    MSDOS
  644.     char *cp;
  645. #endif
  646.  
  647.     if(file == NULLCHAR || path == NULLCHAR)
  648.         return 0;    /* Probably hasn't logged in yet */
  649. #ifdef    MSDOS
  650.     /* Check for characters illegal in MS-DOS file names */
  651.     for(cp = badchars;*cp != '\0';cp++){
  652.         if(strchr(file,*cp) != NULLCHAR)
  653.             return 0;
  654.     }
  655. #endif
  656. #ifndef MAC
  657.     /* The target file must be under the user's allowed search path */
  658.     if(strncmp(file,path,strlen(path)) != 0)
  659.         return 0;
  660. #endif
  661.  
  662.     switch(op){
  663.     case RETR_CMD:
  664.         /* User must have permission to read files */
  665.         return (perms & FTP_READ);
  666.     case DELE_CMD:
  667.     case RMD_CMD:
  668.         /* User must have permission to (over)write files */
  669.         return (perms & FTP_WRITE);
  670.     case STOR_CMD:
  671.     case MKD_CMD:
  672.         /* User must have permission to (over)write files, or permission
  673.          * to create them if the file doesn't already exist
  674.          */
  675.         if(perms & FTP_WRITE)
  676.             return 1;
  677.         if(access(file,2) == -1 && (perms & FTP_CREATE))
  678.             return 1;
  679.         return 0;
  680.     }
  681.     return 0;    /* "can't happen" -- keep lint happy */
  682. }
  683.  
  684. static int near
  685. sendit(ftp,command,file,offset)
  686. struct ftpserv *ftp;
  687. char *command;
  688. char *file;
  689. long offset;
  690. {
  691.     long total;
  692.     struct sockaddr_in dport;
  693.  
  694.     ftp->data = socket(AF_INET,SOCK_STREAM,0);
  695.     dport.sin_family = AF_INET;
  696.     dport.sin_addr.s_addr = INADDR_ANY;
  697.     dport.sin_port = IPPORT_FTPD;
  698.     bind(ftp->data,(char *)&dport,SOCKSIZE);
  699.     usprintf(ftp->control,sending,command,file);
  700.     if(connect(ftp->data,(char *)&ftp->port,SOCKSIZE) == -1){
  701.         fclose(ftp->fp);
  702.         ftp->fp = NULLFILE;
  703.         close_s(ftp->data);
  704.         ftp->data = -1;
  705.         usprintf(ftp->control,noconn);
  706.         return -1;
  707.     }
  708.     /* Do the actual transfer */
  709.     if(fseek(ftp->fp,offset,SEEK_SET))   {  /*restart dk5dc*/
  710.         usprintf(ftp->control,nopos,file);
  711.         return -1;
  712.     }
  713.     total = sendfile(ftp->fp,ftp->data,ftp->type,0);
  714.  
  715.     if(total == -1){
  716.         /* An error occurred on the data connection */
  717.         usprintf(ftp->control,noconn);
  718.         shutdown(ftp->data,2);    /* Blow away data connection */
  719.     } else {
  720.         usprintf(ftp->control,txok);
  721.         close_s(ftp->data);
  722.     }
  723.     ftp->data = -1;
  724.     fclose(ftp->fp);
  725.     ftp->fp = NULLFILE;
  726.     return (total == -1) ? -1 : 0;
  727. }
  728.  
  729. static int near
  730. recvit(ftp,command,file)
  731. struct ftpserv *ftp;
  732. char *command;
  733. char *file;
  734. {
  735.     struct sockaddr_in dport;
  736.     long total;
  737.  
  738.     ftp->data = socket(AF_INET,SOCK_STREAM,0);
  739.     dport.sin_family = AF_INET;
  740.     dport.sin_addr.s_addr = INADDR_ANY;
  741.     dport.sin_port = IPPORT_FTPD;
  742.     bind(ftp->data,(char *)&dport,SOCKSIZE);
  743.     usprintf(ftp->control,sending,command,file);
  744.     if(connect(ftp->data,(char *)&ftp->port,SOCKSIZE) == -1){
  745.         fclose(ftp->fp);
  746.         ftp->fp = NULLFILE;
  747.         close_s(ftp->data);
  748.         ftp->data = -1;
  749.         usprintf(ftp->control,noconn);
  750.         return -1;
  751.     }
  752.     total = recvfile(ftp->fp,ftp->data,ftp->type,0);
  753.  
  754. #ifdef    CPM
  755.     if(ftp->type == ASCII_TYPE)
  756.         putc(CTLZ,ftp->fp);
  757. #endif
  758.  
  759.     if(total == -1) {
  760.         /* An error occurred while writing the file */
  761.         usprintf(ftp->control,writerr,sys_errlist[errno]);
  762.         shutdown(ftp->data,2);    /* Blow it away */
  763.     } else {
  764.         usprintf(ftp->control,rxok);
  765.         close_s(ftp->data);
  766.     }
  767.     ftp->data = -1;
  768.     fclose(ftp->fp);
  769.     ftp->fp = NULLFILE;
  770.     return (total == -1) ? -1 : 0;
  771. }
  772.